import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Between, Repository } from 'typeorm';
import { InjectRedis } from '@nestjs-modules/ioredis';
import Redis from 'ioredis';
import { SysVisitLog } from '../../entities/sys-visit-log.entity';
import * as moment from 'moment';

@Injectable()
export class StatisticsService {
  constructor(
    @InjectRepository(SysVisitLog)
    private visitLogRepository: Repository<SysVisitLog>,
    @InjectRedis() private readonly redis: Redis,
  ) {}

  /**
   * 获取指定天数的访问统计数据
   * @param days 要获取的天数，默认7天
   */
  async getVisitStats(days = 7) {
    // 准备日期范围
    const dates: string[] = [];
    const pvList: number[] = [];
    const ipList: number[] = [];

    const today = moment().startOf('day');

    // 生成过去n天的日期数组
    for (let i = days - 1; i >= 0; i--) {
      const date = moment(today).subtract(i, 'days');
      dates.push(date.format('YYYY-MM-DD'));
    }

    // 尝试从Redis获取统计数据
    for (const date of dates) {
      // 获取日期的PV
      let pv = await this.redis.hget('stats:daily', `pv:${date}`);
      if (!pv) {
        // 如果Redis中没有，从数据库查询
        pv = await this.getPVFromDB(date);
        // 更新Redis缓存
        await this.redis.hset('stats:daily', `pv:${date}`, pv);
      }
      pvList.push(parseInt(pv, 10) || 0);

      // 获取日期的IP数
      let ipCount = await this.redis.scard(`stats:ip:${date}`);
      if (!ipCount) {
        // 如果Redis中没有，从数据库查询
        ipCount = await this.getUniqueIPsFromDB(date);
        // 不更新Redis，因为已经过期的日期可能已失去集合数据
      }
      ipList.push(parseInt(String(ipCount), 10) || 0);
    }

    return {
      dates,
      pvList,
      ipList,
    };
  }

  /**
   * 获取总访问量和访客数
   */
  async getTotalStats() {
    let totalPV = await this.redis.hget('stats:total', 'pv');
    let totalIP = await this.redis.scard('stats:total:ip');

    if (!totalPV) {
      totalPV = await this.getTotalPVFromDB();
      await this.redis.hset('stats:total', 'pv', totalPV);
    }

    if (!totalIP) {
      totalIP = await this.getTotalUniqueIPsFromDB();
      // 不更新Redis的IP集合，因为可能太大
    }

    return {
      totalPV: parseInt(String(totalPV), 10) || 0,
      totalIP: parseInt(String(totalIP), 10) || 0,
    };
  }

  /**
   * 从数据库获取指定日期的PV
   */
  private async getPVFromDB(date: string): Promise<string> {
    const startDate = moment(date).startOf('day').toDate();
    const endDate = moment(date).endOf('day').toDate();

    const count = await this.visitLogRepository.count({
      where: {
        visitTime: Between(startDate, endDate),
      },
    });

    return count.toString();
  }

  /**
   * 从数据库获取指定日期的唯一IP数
   */
  private async getUniqueIPsFromDB(date: string): Promise<number> {
    const startDate = moment(date).startOf('day').toDate();
    const endDate = moment(date).endOf('day').toDate();

    const result = await this.visitLogRepository
      .createQueryBuilder('log')
      .select('COUNT(DISTINCT log.ip)', 'count')
      .where('log.visit_time BETWEEN :startDate AND :endDate', {
        startDate,
        endDate,
      })
      .getRawOne();

    return result?.count || 0;
  }

  /**
   * 从数据库获取总PV
   */
  private async getTotalPVFromDB(): Promise<string> {
    const count = await this.visitLogRepository.count();
    return count.toString();
  }

  /**
   * 从数据库获取总唯一IP数
   */
  private async getTotalUniqueIPsFromDB(): Promise<number> {
    const result = await this.visitLogRepository
      .createQueryBuilder('log')
      .select('COUNT(DISTINCT log.ip)', 'count')
      .getRawOne();

    return result?.count || 0;
  }

  /**
   * 获取统计概览数据
   * 包含今日和总体访问数据，以及与昨日相比的变化率
   */
  async getStatsOverview() {
    const today = moment().format('YYYY-MM-DD');
    const yesterday = moment().subtract(1, 'day').format('YYYY-MM-DD');

    // 获取今日数据
    let todayPv = await this.redis.hget('stats:daily', `pv:${today}`);
    let todayIpCount = await this.redis.scard(`stats:ip:${today}`);

    // 如果Redis中没有，从数据库查询
    if (!todayPv) {
      todayPv = await this.getPVFromDB(today);
      await this.redis.hset('stats:daily', `pv:${today}`, todayPv);
    }

    if (!todayIpCount) {
      todayIpCount = await this.getUniqueIPsFromDB(today);
    }

    // 获取昨日数据
    let yesterdayPv = await this.redis.hget('stats:daily', `pv:${yesterday}`);
    let yesterdayIpCount = await this.redis.scard(`stats:ip:${yesterday}`);

    // 如果Redis中没有，从数据库查询
    if (!yesterdayPv) {
      yesterdayPv = await this.getPVFromDB(yesterday);
      await this.redis.hset('stats:daily', `pv:${yesterday}`, yesterdayPv);
    }

    if (!yesterdayIpCount) {
      yesterdayIpCount = await this.getUniqueIPsFromDB(yesterday);
    }

    // 获取总数据
    let totalPv = await this.redis.hget('stats:total', 'pv');
    let totalIp = await this.redis.scard('stats:total:ip');

    if (!totalPv) {
      totalPv = await this.getTotalPVFromDB();
      await this.redis.hset('stats:total', 'pv', totalPv);
    }

    if (!totalIp) {
      totalIp = await this.getTotalUniqueIPsFromDB();
    }

    // 转换为数值
    const todayPvNum = parseInt(todayPv, 10) || 0;
    const todayIpNum = parseInt(String(todayIpCount), 10) || 0;
    const yesterdayPvNum = parseInt(yesterdayPv, 10) || 0;
    const yesterdayIpNum = parseInt(String(yesterdayIpCount), 10) || 0;
    const totalPvNum = parseInt(String(totalPv), 10) || 0;
    const totalIpNum = parseInt(String(totalIp), 10) || 0;

    // 计算变化率
    const pvChangeRate =
      yesterdayPvNum === 0
        ? 0
        : parseFloat(
            (((todayPvNum - yesterdayPvNum) / yesterdayPvNum) * 100).toFixed(2),
          );

    const ipChangeRate =
      yesterdayIpNum === 0
        ? 0
        : parseFloat(
            (((todayIpNum - yesterdayIpNum) / yesterdayIpNum) * 100).toFixed(2),
          );

    return {
      todayUvCount: todayIpNum,
      totalUvCount: totalIpNum,
      uvGrowthRate: ipChangeRate,
      todayPvCount: todayPvNum,
      totalPvCount: totalPvNum,
      pvGrowthRate: pvChangeRate,
    };
  }
}
